#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
# @version: v1.0
# @author : wlis
# @Email : 1259319710@qq.com
# @Project : g-carbon-bio
# @File : stock_spot_fetcher.py
# @Software: PyCharm
# @time: 2025/2/7 21:20
# @description : 
"""

import time
import pandas as pd
import akshare as ak
from service.csv_help import CSVHelp
from service.models.stock_sh import StockSh
from service.models.stock_sz import StockSz
from service.stocksh_service import StockShService
from service.stocksz_service import StockSzService
from decimal import Decimal


# 全局变量，控制是否打印调试信息
DEBUG_PRINT = True  # 设置为 True 以启用打印，False 则禁用打印

class StockSpotFetcher:
    def __init__(self):
        # 初始化服务类
        self.stocksh_service = StockShService()
        self.stocksz_service = StockSzService()

    def fetch_stock_data(self, stock_df, stock_service, file_name, stock_model):
        """
        获取股票数据并保存到CSV文件和数据库中
        :param stock_df: 股票数据的DataFrame
        :param stock_service: 股票服务类（上海或深圳）
        :param file_name: 保存的CSV文件名
        :param stock_model: 股票模型类（上海或深圳）
        """
        stock_add_list = []

        # 遍历每一行股票数据
        for index, row in stock_df.iterrows():
            code = row['代码']
            # 添加过滤条件，如果相关数据为空则跳过该股票
            if pd.isna(row['最新价']) or pd.isna(row['涨跌幅']) or pd.isna(row['涨跌额']) or pd.isna(
                    row['成交量']) or pd.isna(row['成交额']):
                if DEBUG_PRINT:
                    print(f"股票 {code} 的相关数据为空，跳过该股票。")
                continue  # 如果有字段为空，则跳过该股票

            # 获取股票的实时数据
            stock_intraday_em_df = self.get_intraday_data(code)

            # 获取成功的打印信息
            if stock_intraday_em_df is not None:
                if DEBUG_PRINT:
                    print(f"成功获取股票 {code} 的实时数据。")
            else:
                # 获取失败的打印信息
                if DEBUG_PRINT:
                    print(f"未能获取股票 {code} 的实时数据，跳过该股票。")
                continue

            # 处理实时数据，过滤掉不符合条件的数据
            filtered_df = self.process_intraday_data(stock_intraday_em_df)
            # 计算买卖盘数据
            buy_volume, sell_volume, neutral_volume, buy_amount, sell_amount, neutral_amount = self.calculate_volumes(
                filtered_df)

            # 创建股票模型对象
            stock = stock_model(
                0, code, row['名称'], row['最新价'], row['涨跌幅'], row['涨跌额'], row['成交量'],
                row['成交额'], row['振幅'], row['最高'], row['最低'], row['今开'], row['昨收'],
                row['量比'], row['换手率'], row['市盈率-动态'], row['市净率'], row['总市值'],
                row['流通市值'], row['涨速'], row['5分钟涨跌'], row['60日涨跌幅'],
                row['年初至今涨跌幅'], None,
                buy_volume, sell_volume, neutral_volume,
                buy_amount, sell_amount, neutral_amount
            )

            # 将股票对象添加到列表中
            stock_add_list.append(stock)

        # 保存到CSV文件
        self.save_to_csv(stock_add_list, file_name)
        # 批量插入到数据库
        stock_service.add_list_am(stock_add_list)

    def get_intraday_data(self, code: str, max_retries: int = 3) -> dict | None:
        """
        获取股票的实时数据
        :param code: 股票代码
        :param max_retries: 最大重试次数
        :return: 实时数据的DataFrame或None
        """
        attempt = 0
        while attempt < max_retries:
            try:
                return ak.stock_intraday_em(symbol=code)
            except Exception as e:
                attempt += 1
                time.sleep(1)
                if DEBUG_PRINT:
                    print(f"尝试获取 {code} 的实时数据失败: {e}")
                if attempt >= max_retries:
                    if DEBUG_PRINT:
                        print(f"获取 {code} 的实时数据失败次数已达 {max_retries} 次，将跳过该股票。")
                    return None

    def process_intraday_data(self, stock_intraday_em_df: pd.DataFrame) -> pd.DataFrame:
        """
        处理实时数据，过滤掉不符合条件的数据
        :param stock_intraday_em_df: 实时数据的DataFrame
        :return: 过滤后的DataFrame
        """
        # 将时间列转换为 datetime 格式
        stock_intraday_em_df['时间'] = pd.to_datetime(stock_intraday_em_df['时间'], format='%H:%M:%S')

        # 定义截止时间
        cutoff_time = pd.to_datetime('09:32:00', format='%H:%M:%S')

        # 返回在截止时间之前的所有数据
        return stock_intraday_em_df[stock_intraday_em_df['时间'] < cutoff_time]

    def calculate_volumes(self, filtered_df: pd.DataFrame) -> tuple[
        Decimal, Decimal, Decimal, Decimal, Decimal, Decimal]:
        """
        计算买卖盘数据
        :param filtered_df: 过滤后的实时数据
        :return: 买卖盘数据（买盘量、卖盘量、中性盘量、买盘金额、卖盘金额、中性盘金额）
        """
        # 初始化为 Decimal 类型
        buy_volume = sell_volume = neutral_volume = Decimal('0.00')
        buy_amount = sell_amount = neutral_amount = Decimal('0.00')

        # 遍历每一行数据
        for index, row in filtered_df.iterrows():
            # 将手数和成交价转换为 Decimal 类型
            hand_count = Decimal(row['手数'])*100
            transaction_price = Decimal(row['成交价'])

            # 根据买卖盘性质累加相应的量和金额
            if row['买卖盘性质'] == '买盘':
                buy_volume += hand_count
                buy_amount += hand_count * transaction_price
            elif row['买卖盘性质'] == '卖盘':
                sell_volume += hand_count
                sell_amount += hand_count * transaction_price
            elif row['买卖盘性质'] == '中性盘':
                neutral_volume += hand_count
                neutral_amount += hand_count * transaction_price

        # 确保每个量化为两位小数
        buy_volume = buy_volume.quantize(Decimal('0.00'))
        sell_volume = sell_volume.quantize(Decimal('0.00'))
        neutral_volume = neutral_volume.quantize(Decimal('0.00'))
        buy_amount = buy_amount.quantize(Decimal('0.00'))
        sell_amount = sell_amount.quantize(Decimal('0.00'))
        neutral_amount = neutral_amount.quantize(Decimal('0.00'))

        return buy_volume, sell_volume, neutral_volume, buy_amount, sell_amount, neutral_amount

    def save_to_csv(self, stock_add_list, file_name):
        """
        将股票数据保存到CSV文件
        :param stock_add_list: 股票数据列表
        :param file_name: 保存的文件名
        """
        stock_data = pd.DataFrame([s.__dict__ for s in stock_add_list])
        csv_helper = CSVHelp()
        csv_helper.write_to_csv(stock_data, file_name)

    def insert_stock_sh_spot_am(self):
        """插入上海股票的最新数据（上午数据）"""
        start_time = time.time()  # 记录开始时间
        print("开始插入上海股票数据...")

        # 获取上海股票的实时数据
        stock_sh_a_spot_em_df = ak.stock_sh_a_spot_em()
        # 处理并保存数据
        self.fetch_stock_data(stock_sh_a_spot_em_df, self.stocksh_service, 'stock_sh_spot_am.csv', StockSh)

        end_time = time.time()  # 记录结束时间
        print(f"上海股票数据插入完成，总耗时: {end_time - start_time:.2f}秒")

    def insert_stock_sz_spot_am(self):
        """插入深圳股票的最新数据（上午数据）"""
        start_time = time.time()  # 记录开始时间
        print("开始插入深圳股票数据...")

        # 获取深圳股票的实时数据
        stock_sz_a_spot_em_df = ak.stock_sz_a_spot_em()
        # 处理并保存数据
        self.fetch_stock_data(stock_sz_a_spot_em_df, self.stocksz_service, 'stock_sz_spot_am.csv', StockSz)

        end_time = time.time()  # 记录结束时间
        print(f"深圳股票数据插入完成，总耗时: {end_time - start_time:.2f}秒")


# 主程序
# if __name__ == "__main__":
#     import akshare as ak
#     import datetime
#
#     # 记录调用方法的时间
#     start_time = datetime.datetime.now()
#
#     # 调用 ak.stock_fund_flow_individual 方法
#     stock_fund_flow_individual_df = ak.stock_fund_flow_individual(symbol="即时")
#
#     # 记录调用结束的时间
#     end_time = datetime.datetime.now()
#
#     # 计算耗时
#     time_delta = end_time - start_time
#     minutes = time_delta.seconds // 60  # 计算分钟
#     seconds = time_delta.seconds % 60  # 计算秒
#
#     # 打印调用方法的耗时
#     print(f"调用方法耗时: {minutes} 分钟 {seconds} 秒")
#
#     # 打印获取的数据
#     print(stock_fund_flow_individual_df)
    # fetcher = StockSpotFetcher()
    # fetcher.insert_stock_sh_spot_am()  # 插入上海股票数据
    # fetcher.insert_stock_sz_spot_am()  # 插入深圳股票数据



